package bavaria.hightec.banking;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;

import bavaria.hightec.conditions.DepositAccountConditions;
import bavaria.hightec.conditions.GiroAccountConditions;
import bavaria.hightec.conditions.Conditions.runtime;
import bavaria.hightec.conditions.RateOfInterest;
import bavaria.hightec.exceptions.*;
import bavaria.hightec.time.TimeEmitter;

public class BankImpl implements BankCustomerView,BankAdministration,B2B{
	private String bankName;
	private int accountNumber=1000;
	private Map<Integer, Account> account= new HashMap<Integer, Account>();
	public static Calendar c2=Calendar.getInstance();
	public static final int INTERESTTIMEFAKTOR=86400;
	private RateOfInterest rateOfInterest = new RateOfInterest(0.4,11.8); //creditInterest, debitInterest
	private static Map<String,ResourceBundle > local = new HashMap<String,ResourceBundle>();
	private static String localeKey;
	
	
	public BankImpl(String name,String local){
		BankImpl.local.put("DE", ResourceBundle.getBundle("statement_de_de",new Locale("de","de")));
		BankImpl.local.put("EN", ResourceBundle.getBundle("statement_en_en",new Locale("en","en")));
		localeKey=local;
		bankName=name;
		TimeEmitter.getInstance();
        Timer interestTimer = new Timer();
        interestTimer.scheduleAtFixedRate(
            	new TimerTask() {
            		public void run()  {
            			BankImpl.this.modifyInterestCalendar();
            			try {
            				BankImpl.this.chargeInterest();
            			} catch (OverCheckException e) {
            				System.out.println(e.getMessage());
            			}
            		}
            	},
            	1000, 
            	(long) TimeEmitter.getPeriod());
	}
	
	private void modifyInterestCalendar(){
		c2.add(Calendar.SECOND, INTERESTTIMEFAKTOR);
	}
	
	public static ResourceBundle getLocale(){
		return local.get(localeKey);
	}
	
	
	
   public void setConditions(double soll,double hab){
	   rateOfInterest.setDebit(soll);
	   rateOfInterest.setInterest(hab);
	   
   }
   
   public String getGiroConditions(){
	   String s = "Girokonto. Habenzins: " + rateOfInterest.getCreditInterest()+ " " + "Sollzins: " +rateOfInterest.getDebitInterest() + " Bonitaeten: " +GiroAccountConditions.CreditHistory.THREE+" "+ GiroAccountConditions.getCreditHistory(GiroAccountConditions.CreditHistory.THREE) +" "+ GiroAccountConditions.CreditHistory.TWO + " " + GiroAccountConditions.getCreditHistory(GiroAccountConditions.CreditHistory.TWO)+" "+ GiroAccountConditions.CreditHistory.ONE + " " + GiroAccountConditions.getCreditHistory(GiroAccountConditions.CreditHistory.ONE);
	   return s;
   }
   
   public String getDepositConditions(){
	   String t = "Festgeldkonto. Laufzeit/Zins : " + runtime.THREE +" "+DepositAccountConditions.getCreditInterest(runtime.THREE)+" "+ runtime.SIX +" "+DepositAccountConditions.getCreditInterest(runtime.SIX)+" "+ runtime.TWELVE +" "+DepositAccountConditions.getCreditInterest(runtime.TWELVE);
	   return t;
   }
    
    	
	public String createGiroAccount(String name){
			GiroAccountConditions konditionen = new GiroAccountConditions();
			Date creation = TimeEmitter.getInstance().getCalendar().getTime();
			account.put(accountNumber,new GiroAccount(creation,konditionen,rateOfInterest,accountNumber,name));
			String s = "Girokonto am " + creation+ " erstellt. Kontonr: " + accountNumber + " Besitzer: " + name;
			accountNumber++;
			return s;
	}
	
	public String createDepositAccount(String name,runtime runtime){
			DepositAccountConditions konditionen= new DepositAccountConditions(runtime);
			Date creation= TimeEmitter.getInstance().getCalendar().getTime();
			account.put(accountNumber,new DepositAccount(creation,konditionen,accountNumber,name));
			String s = "Festgeldkonto am " + creation+" erstellt. Kontonr: " + accountNumber + " Besitzer: " + name;
			accountNumber++;
			return s;
	}
	
	public Money balance(int accountNumber){
		Money money = new Money(account.get(accountNumber).getBalance(),account.get(accountNumber).getCurrency());
		return money;
		
	}


	public void withdraw(int accountNumber, Money betrag,String grund)throws OverCheckException {
		account.get(accountNumber).debitEntry(betrag, grund);
		
	}

	
	public void fund(int accountNumber, Money amount,String matter) throws OverCheckException {
		account.get(accountNumber).creditEntry(amount, matter);
	}
	
	public void transaction(int accountNumber, int accountOfDestination, Money amount,String matter) throws OverCheckException {
		account.get(accountNumber).debitEntry(amount, matter);
		account.get(accountNumber).creditEntry(amount, matter);		
	}
	
	public void transaction(String banknameOfDestination,int accountNumber, int accountOfDestination, Money amount,String matter) throws OverCheckException {
		  BankRegistry bank;
		  bank = BankRegistry.getInstance();
		  bank.lookup(bankName).withdraw(accountNumber, amount, matter);
		  bank.lookup(banknameOfDestination).fund(accountOfDestination, amount, matter);
	} 
	
	public void chargeInterest() throws OverCheckException{
		for(Integer key:account.keySet()){
			account.get(key).chargeInterest();
		}
	}
	
	public String list(){
		for(Integer key:account.keySet()){
			return account.get(key).toString();
		}
		return null;
	}	
	
	public void statement(int accountNumber, OutputStream out, String mimeType) throws IOException{
		if(account.containsKey(accountNumber)){
			Account account = getAccount(accountNumber);
			String statement = account.statement(mimeType);
		
			try {
				out.write(statement.getBytes());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		else
			throw new UnknownAccountException("unknown account");
	}

	private Account getAccount(int accountNumber) {
		return account.get(accountNumber);
	}

	@Override
	public void sort(String type,int accountNumber) {
		account.get(accountNumber).sort(type);
		
	}

	@Override
	public boolean accountNumberExists(int accountnumber) {
		if(account.get(accountnumber) != null)
			return true;
		else
			return false;
	}


}



	

